#pragma once

#include "Generics.h"
#include "DataFeeds.h"
#include <string>
#include <vector>

namespace StorageEngine {
	class Storage;
}

namespace ServerLogic {
	typedef enum {
		Authorisation,
		Transaction,
		Update} SessionState;

	class POPException : public Generic::Exception {
	public:
		POPException(std::string message);
	};

	class POPAuthFailedException : public POPException {
	public:
		POPAuthFailedException(std::string message);
	};

	class POPMaildropLockException : public POPException {
	public:
		POPMaildropLockException(std::string message);
	};

	class POPNoSuchMessageException : public POPException {
	public:
		POPNoSuchMessageException(std::string message);
	};

	class POPInvalidMailManagerException : public POPException {
	public:
		POPInvalidMailManagerException(std::string message);
	};

	class POPInvalidDataFeedException : public POPException {
	public:
		POPInvalidDataFeedException(std::string message);
	};

	class MailStub {
		int _size, _msg;
	public:
		MailStub(int msg, int size);
		int Size();
		int Msg();
	};

	typedef std::vector<MailStub> MailList;

	struct MaildropInfo {
		int Messages, Octets;
		MaildropInfo();
	};

	class Mail {
		std::string _body;
		std::string from;
		std::string to;
		std::string date;
		std::string subject;
	public:
		Mail(std::string & body);
		std::string Body();
	};

	class IMailManager {
	public:
		virtual MailList ListAll() = 0;
		virtual MailStub List(int msg) = 0;
		virtual MaildropInfo Stat() = 0;
		virtual Mail Retrieve(int msg) = 0;
		virtual void Delete(int msg) = 0;
		virtual void Reset() = 0;
		virtual void AcquireLock() = 0;
		virtual void ReleaseLock() = 0;
		virtual void UpdateMaildrop() = 0;
	};

	class UserAccount {
		std::string _user;
		std::string _pass;
		bool _authenticated;
		IMailManager * _manager;
	public:
		UserAccount(std::string user, std::string pass, IMailManager * manager);
		bool Authenticate(std::string pass);
		IMailManager * GetManager();
	};

	class Session;
	class ServerCore {
		static std::vector <std::string> _Parts(std::string message);
		static void _ToLower(std::string & message);
		static DWORD WINAPI _StartSession (LPVOID param);
	public:
		static void Execute(std::string command, Session * session);
		void Start();
	};

	class Session {
		SessionState _state;
		UserAccount * _user;
		DataFeeds::IDataFeed * _feed;
		bool _quit_invoked;
		void _WrongState();
		void _OK(std::string message = "");
		void _ERR(std::string message = "");
		void _Dot();
	public:
		Session(DataFeeds::IDataFeed * feed);
		void Run();
	// Tymczasowo:
	public:
		void LIST();
		void LIST(int msg);
		void STAT();
		void RETR(int msg);
		void DELE(int msg);
		void RSET();
		void USER(std::string user);
		void PASS(std::string pass);
		void QUIT();
		void Unknown();
	};
}